home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Rozne / HTTrack 3.40-2 / httrack-3.40-2.exe / {app} / src / mmsrip / mms.c < prev    next >
C/C++ Source or Header  |  2006-01-23  |  34KB  |  1,240 lines

  1. /*
  2.  * $RCSfile: mms.c,v $
  3.  * $Date: 2006/01/23 20:30:43 $ - $Revision: 1.33 $
  4.  *
  5.  * This file is distributed as a part of MMSRIP ( MMS Ripper ).
  6.  * Copyright (c) 2005-2006 Nicolas BENOIT
  7.  *
  8.  * It is highly based on the work of SDP Multimedia and Major MMS.
  9.  * They deserve all the credits for it.
  10.  *
  11.  * This program is free software; you can redistribute it and/or modify it
  12.  * under the terms of the GNU General Public License as published by the
  13.  * Free Software Foundation; either version 2, or (at your option) any
  14.  * later version.
  15.  *
  16.  * This program is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  *
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with this program; if not, write to the Free Software
  23.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  *
  25.  */
  26.  
  27.  
  28. #define _GNU_SOURCE
  29.  
  30. #ifdef _WIN32
  31. #include <winsock2.h>
  32. #else
  33. #include <unistd.h>
  34. #include <strings.h>
  35. #include <sys/socket.h>
  36. #include <netinet/in.h>
  37. #include <netdb.h>
  38. #endif
  39.  
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <sys/stat.h>
  43. #include <fcntl.h>
  44. #include <stdlib.h>
  45. #include <errno.h>
  46.  
  47. #include "common.h"
  48. #include "mms.h"
  49. #include "error.h"
  50.  
  51.  
  52. /*
  53.  * Put 32 bits inside a command buffer.
  54.  */
  55. static void
  56. mms_put_32 ( MMS_PACKET *pak,
  57.              uint32_t value )
  58. {
  59.   pak->buf[pak->num_bytes  ] = value % 256;
  60.   value = value >> 8;
  61.   pak->buf[pak->num_bytes+1] = value % 256 ;
  62.   value = value >> 8;
  63.   pak->buf[pak->num_bytes+2] = value % 256 ;
  64.   value = value >> 8;
  65.   pak->buf[pak->num_bytes+3] = value % 256 ;
  66.  
  67.   pak->num_bytes += 4;
  68.   return;
  69. }
  70.  
  71.  
  72. /*
  73.  * Returns the 32 bits located at specified offset.
  74.  */
  75. static uint32_t
  76. mms_get_32 ( const unsigned char *buf,
  77.              const int offset )
  78. {
  79.   return ( (((uint32_t)buf[offset+0]) << 0)  |
  80.            (((uint32_t)buf[offset+1]) << 8)  |
  81.            (((uint32_t)buf[offset+2]) << 16) |
  82.            (((uint32_t)buf[offset+3]) << 24) );
  83. }
  84.  
  85.  
  86. /*
  87.  * Returns the 64 bits located at specified offset.
  88.  */
  89. static uint64_t
  90. mms_get_64 ( const unsigned char *buf,
  91.              const int offset )
  92. {
  93.   return ( (((uint64_t)buf[offset+0]) << 0)  |
  94.            (((uint64_t)buf[offset+1]) << 8)  |
  95.            (((uint64_t)buf[offset+2]) << 16) |
  96.            (((uint64_t)buf[offset+3]) << 24) |
  97.            (((uint64_t)buf[offset+4]) << 32) |
  98.            (((uint64_t)buf[offset+5]) << 40) |
  99.            (((uint64_t)buf[offset+6]) << 48) |
  100.            (((uint64_t)buf[offset+7]) << 56) );
  101. }
  102.  
  103.  
  104. /*
  105.  * Converts a string into a UTF-16 string.
  106.  */
  107. static void
  108. mms_string_utf16 ( uint8_t *dest,
  109.                    unsigned char *src,
  110.                    const ssize_t len )
  111. {
  112.   ssize_t i;
  113.   memset ( dest, 0, len );
  114.  
  115.   for ( i=0; i<len; ++i )
  116.     {
  117.       dest[i*2] = src[i];
  118.       dest[i*2+1] = 0;
  119.     }
  120.  
  121.   dest[i*2] = 0;
  122.   dest[i*2+1] = 0;
  123.   return;
  124. }
  125.  
  126.  
  127. /*
  128.  * Checks a URL for a correct MMS protocol.
  129.  * Returns the host name index if the protocol is valid, else it returns MMS_RET_ERROR.
  130.  */
  131. static int
  132. mms_check_protocol ( const char *url )
  133. {
  134.   static const char *proto[] = { "mms://", "mmsu://", "mmst://", "mmsh://", NULL };
  135.   static const int proto_len[] = { 6, 7, 7, 7, 0 };
  136.   register const char *p = proto[0];
  137.   int i = 0;
  138.  
  139.   while ( p != NULL )
  140.     {
  141.       if ( strncmp ( url, p, proto_len[i] ) == 0 )
  142.         return proto_len[i];
  143.  
  144.       p = proto[++i];
  145.     }
  146.  
  147.   return MMS_RET_ERROR;
  148. }
  149.  
  150.  
  151. /*
  152.  * Prints out a command packet (debug purpose).
  153.  */
  154. static void
  155. mms_print_packet ( FILE *stddebug,
  156.                    const MMS_PACKET *pak,
  157.                    const ssize_t length,
  158.                    const int orig )
  159. {
  160.   ssize_t i;
  161.   unsigned char c;
  162.  
  163.   fprintf ( stddebug, "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n" );
  164.  
  165.   if ( orig == MMS_SERVER )
  166.     fprintf ( stddebug, " command from server (%d bytes)\n", length );
  167.   else
  168.     fprintf ( stddebug, " command from client (%d bytes)\n", length );
  169.  
  170.   fprintf ( stddebug, " start sequence: 0x%08x\n", mms_get_32(pak->buf, 0) );
  171.   fprintf ( stddebug, " command id:     0x%08x\n", mms_get_32(pak->buf, 4) );
  172.   fprintf ( stddebug, " length:         0x%8x \n", mms_get_32(pak->buf, 8) );
  173.   fprintf ( stddebug, " len8:           0x%8x \n", mms_get_32(pak->buf, 16) );
  174.   fprintf ( stddebug, " sequence #:     0x%08x\n", mms_get_32(pak->buf, 20) );
  175.   fprintf ( stddebug, " len8  (II):     0x%8x \n", mms_get_32(pak->buf, 32) );
  176.   fprintf ( stddebug, " dir | comm:     0x%08x\n", mms_get_32(pak->buf, 36) );
  177.   fprintf ( stddebug, " switches:       0x%08x\n", mms_get_32(pak->buf, 40) );
  178.  
  179.   fprintf ( stddebug, "\nascii contents:\n" );
  180.  
  181.   for ( i=48; i<length; i+=2 )
  182.     {
  183.       c = pak->buf[i];
  184.  
  185.       if ( ( c>=32 ) && ( c<=128 ) )
  186.         fprintf ( stddebug, "%c", c );
  187.       else
  188.         fprintf ( stddebug, "." );
  189.     }
  190.  
  191.   fprintf ( stddebug, "\n\npackage hexdump:\n " );
  192.  
  193.   i = 0;
  194.  
  195.   while ( 1 )
  196.     {
  197.       c = pak->buf[i];
  198.       fprintf ( stddebug, "%02x", c );
  199.  
  200.       ++i;
  201.  
  202.       if ( i < length )
  203.         {
  204.           if ( (i % 16) == 0 )
  205.             fprintf ( stddebug, "\n" );
  206.  
  207.           if ( (i % 2) == 0 )
  208.             fprintf ( stddebug, " " );
  209.         }
  210.       else
  211.         break;
  212.     }
  213.  
  214.   fprintf ( stddebug, "\n\n" );
  215.   fflush ( stddebug );
  216.   return;
  217. }
  218.  
  219.  
  220. /*
  221.  * Sends a command packet to the server.
  222.  * Returns MMS_RET_SUCCESS if success, MMS_RET_ERROR either.
  223.  */
  224. static int
  225. mms_send_packet ( MMS *mms,
  226.                   const int command,
  227.                   const uint32_t switches, 
  228.                   const uint32_t extra,
  229.                   const ssize_t length,
  230.                   const uint8_t *data )
  231. {  
  232.   MMS_PACKET pak;
  233.   ssize_t written_len;
  234.  
  235.   const ssize_t len8 = ( length + (length%8) ) / 8;
  236.  
  237.   pak.num_bytes = 0;
  238.  
  239.   mms_put_32 ( &pak, 0x00000001 ); /* start sequence */
  240.   mms_put_32 ( &pak, 0xB00BFACE ); /* #-)) */
  241.   mms_put_32 ( &pak, length + 32 );
  242.   mms_put_32 ( &pak, 0x20534d4d ); /* protocol type "MMS " */
  243.   mms_put_32 ( &pak, len8 + 4 );
  244.   mms_put_32 ( &pak, mms->seq_num++ );
  245.   mms_put_32 ( &pak, 0x0 );        /* unknown */
  246.   mms_put_32 ( &pak, 0x0 );
  247.   mms_put_32 ( &pak, 2+len8 );
  248.   mms_put_32 ( &pak, 0x00030000 | command ); /* dir | command */
  249.   mms_put_32 ( &pak, switches );
  250.   mms_put_32 ( &pak, extra );
  251.  
  252.   memcpy ( &pak.buf[48], data, length );
  253.  
  254.   written_len = write ( mms->socket, pak.buf, length+48 );
  255.  
  256.   if ( written_len == -1 )
  257.     {
  258.       if ( !mms->quiet )
  259. #ifdef HAVE_VSNPRINTF
  260.         error ( "mms_send_packet", "write() said: %s", strerror(errno) );
  261. #else
  262.         error ( "mms_send_packet", "write() failed" );
  263. #endif
  264.  
  265.       return MMS_RET_ERROR;
  266.     }
  267.   else if ( written_len != (length+48) )
  268.     {
  269.       if ( !mms->quiet )
  270.         error ( "mms_send_packet", "did not write enough bytes" );
  271.  
  272.       return MMS_RET_ERROR;
  273.     }
  274.  
  275.   if ( mms->stddebug != NULL )
  276.     mms_print_packet ( mms->stddebug, &pak, length+48, MMS_CLIENT );
  277.  
  278.   return MMS_RET_SUCCESS;
  279. }
  280.  
  281.  
  282. /*
  283.  * Reads some bytes from the socket.
  284.  * This is blocking until we don't have the required amount of bytes.
  285.  * Returns MMS_RET_SUCCESS if success, MMS_RET_ERROR either.
  286.  */
  287. static int
  288. mms_recv_packet ( const int s,
  289.                   MMS_PACKET *pak,
  290.                   size_t count,
  291.                   const int quiet )
  292. {
  293.   ssize_t read_len, total;
  294.   total = 0;
  295.  
  296.   if ( MMS_BUF_SIZE < count )
  297.     {
  298.       if ( !quiet )
  299.         warning ( "mms_recv_packet", "caller is too greedy" );
  300.  
  301.       count = MMS_BUF_SIZE;
  302.     }
  303.  
  304.   while ( total < count )
  305.     {
  306.       read_len = read ( s, &pak->buf[total], count-total );
  307.  
  308.       if ( read_len == -1 )
  309.         {
  310.           if ( !quiet )
  311. #ifdef HAVE_VSNPRINTF
  312.             error ( "mms_recv_packet", "read() said: %s", strerror(errno) );
  313. #else
  314.             error ( "mms_recv_packet", "read() failed" );
  315. #endif
  316.  
  317.           return MMS_RET_ERROR;
  318.         }
  319.  
  320.       total += read_len;
  321.     }
  322.  
  323.   return MMS_RET_SUCCESS;
  324. }
  325.  
  326.  
  327. /*
  328.  * Gets server's command.
  329.  * The first 8 bytes can be skipped setting offset to 8.
  330.  * It writes the packet length in the provided storage.
  331.  * Returns command ID, MMS_CMD_INVALID if error.
  332.  */
  333. static int
  334. mms_recv_cmd_packet ( const int s,
  335.                       MMS_PACKET *pak,
  336.                       ssize_t *packet_len,
  337.                       const int offset,
  338.                       const int quiet )
  339. {
  340.   MMS_PACKET tmp;
  341.  
  342.   if ( ( offset > 8 ) || ( offset < 0 ) )
  343.     {
  344.       if ( !quiet )
  345.         error ( "mms_recv_cmd_packet", "provided offset is invalid" );
  346.  
  347.       return MMS_RET_ERROR;
  348.     }
  349.  
  350.   if ( mms_recv_packet ( s, &tmp, 12-offset, quiet ) != 0 )
  351.     {
  352.       if ( !quiet )
  353.         error ( "mms_recv_cmd_packet", "unable to get packet header" );
  354.  
  355.       return MMS_RET_ERROR;
  356.     }
  357.  
  358.   memcpy ( &pak->buf[offset], tmp.buf, 12-offset );
  359.  
  360.   if ( offset == 0 )
  361.     {
  362.       if ( mms_get_32(pak->buf, 4) != 0xb00bface ) /* probably a coincidence... */
  363.         {
  364.           if ( !quiet )
  365.             error ( "mms_recv_cmd_packet", "answer should have been a cmd packet" );
  366.  
  367.           return MMS_RET_ERROR;
  368.         }
  369.     }
  370.  
  371.   memcpy ( packet_len, &pak->buf[8], 4 );
  372.   *packet_len = mms_get_32 ( (unsigned char *) packet_len, 0 ) + 4;
  373.  
  374.   if ( ( *packet_len + 12 ) > MMS_BUF_SIZE )
  375.     {
  376.       if ( !quiet )
  377.         error ( "mms_recv_cmd_packet", "incoming packet is too big for me" );
  378.  
  379.       return MMS_RET_ERROR;
  380.     }
  381.  
  382.   if ( mms_recv_packet ( s, &tmp, *packet_len, quiet ) != 0 )
  383.     {
  384.       if ( !quiet )
  385.         error ( "mms_recv_cmd_packet", "unable to get packet body" );
  386.  
  387.       return MMS_RET_ERROR;
  388.     }
  389.  
  390.   memcpy ( &pak->buf[12], tmp.buf, *packet_len );
  391.  
  392.   return ( mms_get_32(pak->buf, 36) & 0xFFFF );
  393. }
  394.  
  395.  
  396. /*
  397.  * Gets the header of the ASF/WMV stream/file.
  398.  * Returns the amount of bytes received, MMS_RET_ERROR if we encounter an error.
  399.  */
  400. static ssize_t
  401. mms_recv_header_packet ( MMS *mms,
  402.                          MMS_PACKET *pak )
  403. {
  404.   MMS_PACKET pre_header;
  405.   MMS_PACKET tmp;
  406.   ssize_t header_len;
  407.   ssize_t packet_len;
  408.  
  409.   header_len = 0;
  410.  
  411.   while ( 1 )
  412.     {
  413.       if ( mms_recv_packet ( mms->socket, &pre_header, 8, mms->quiet ) != 0 )
  414.         {
  415.           if ( !mms->quiet )
  416.             error ( "mms_recv_header_packet", "unable to get pre-header" );
  417.  
  418.           return MMS_RET_ERROR;
  419.         }
  420.  
  421.       if ( pre_header.buf[4] == 0x02 )
  422.         {
  423.           if ( mms->stddebug != NULL )
  424.             {
  425.               fprintf ( mms->stddebug, "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n" );
  426.               fprintf ( mms->stddebug, " getting header packet from server\n\n" );
  427.             }
  428.  
  429.           if ( mms->stddebug != NULL )
  430.             {
  431.               static int i; /* static, so we don't recreate it for each call */
  432.  
  433.               for ( i=0; i<8; ++i )
  434.                 fprintf ( mms->stddebug, "pre_header.buf[%d] = 0x%02x (%d)\n", i, pre_header.buf[i], pre_header.buf[i] );
  435.             }
  436.  
  437.           packet_len = ( pre_header.buf[7] << 8 | pre_header.buf[6] ) - 8;
  438.  
  439.           if ( mms->stddebug != NULL )
  440.             fprintf ( mms->stddebug, "\nASF Header Packet (%d bytes)\n", packet_len );
  441.  
  442.           if ( mms_recv_packet ( mms->socket, &tmp, packet_len, mms->quiet ) != 0 )
  443.             {
  444.               if ( !mms->quiet )
  445.                 error ( "mms_recv_header_packet", "unable to get header" );
  446.  
  447.               return MMS_RET_ERROR;
  448.             }
  449.  
  450.           if ( ( header_len + packet_len ) > MMS_BUF_SIZE )
  451.             {
  452.               if ( !mms->quiet )
  453.                 error ( "mms_recv_header_packet", "total header length is too big for me" );
  454.  
  455.               return MMS_RET_ERROR;
  456.             }
  457.  
  458.           memcpy ( &pak->buf[header_len], tmp.buf, packet_len );
  459.  
  460.           header_len += packet_len;
  461.  
  462.           if ( mms->stddebug != NULL )
  463.             fprintf ( mms->stddebug, "\n" );
  464.  
  465.           /* test if end of header is reached */
  466.           if ( ( pak->buf[header_len-1] == 1) &&
  467.                ( pak->buf[header_len-2] == 1 ) )
  468.             return header_len;
  469.         }
  470.       else /* we might receive an ack or an error */
  471.         {
  472.           int command = mms_recv_cmd_packet ( mms->socket, &tmp, &packet_len, 8, mms->quiet );
  473.  
  474.           if ( command == -1 )
  475.             {
  476.               if ( !mms->quiet )
  477.                 error ( "mms_recv_header_packet", "unable to get cmd packet" );
  478.  
  479.               return MMS_RET_ERROR;
  480.             }
  481.  
  482.           memcpy ( tmp.buf, pre_header.buf, 8 );
  483.  
  484.           if ( mms->stddebug != NULL )
  485.             mms_print_packet ( mms->stddebug, &tmp, packet_len, MMS_SERVER );
  486.  
  487.           if ( command == MMS_CMD_PING )
  488.             mms_send_packet ( mms, MMS_CMD_PONG, 0, 0, 0, tmp.buf );
  489.           else if ( command != MMS_CMD_HEADER_DATA )
  490.             {
  491.               if ( !mms->quiet )
  492. #ifdef HAVE_VSNPRINTF
  493.                 error ( "mms_recv_header_packet", "unknown command 0x%02x\n", command );
  494. #else
  495.                 error ( "mms_recv_header_packet", "unknown command\n" );
  496. #endif
  497.  
  498.               return MMS_RET_ERROR;
  499.             }
  500.         }
  501.     }
  502. }
  503.  
  504.  
  505. /*
  506.  * Interprates the header (media packet size, etc.).
  507.  * Returns the size of a media packet (should be != 0 ).
  508.  */
  509. static ssize_t
  510. mms_interp_header ( MMS *mms,
  511.                     const uint8_t *header,
  512.                     const ssize_t header_len )
  513. {
  514.   int i;
  515.   ssize_t packet_length = 0;
  516.  
  517.   mms->expected_file_size = header_len;
  518.  
  519.   if ( mms->stddebug != NULL )
  520.     {
  521.       fprintf ( mms->stddebug, "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n" );
  522.       fprintf ( mms->stddebug, " header interpretation\n\n" );
  523.     }
  524.  
  525.   /* parse header */
  526.   mms->num_stream_ids = 0;
  527.   i = 30;
  528.  
  529.   while ( i < header_len )
  530.     {
  531.       uint64_t  guid_1, guid_2, length;
  532.  
  533.       if ( mms->stddebug != NULL )
  534.         {
  535.           /* this is MS GUID format */
  536.           fprintf ( mms->stddebug, "{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
  537.                                    header[i+3], header[i+2], header[i+1], header[i+0],
  538.                                    header[i+5], header[i+4], header[i+7], header[i+6],
  539.                                    header[i+8], header[i+9], header[i+10], header[i+11],
  540.                                    header[i+12], header[i+13], header[i+14], header[i+15] );
  541.         }
  542.  
  543.       guid_2 = mms_get_64 ( header, i );
  544.       i += 8;
  545.  
  546.       guid_1 = mms_get_64 ( header, i );
  547.       i += 8;
  548.  
  549.       length = mms_get_64 ( header, i );
  550.       i += 8;
  551.  
  552.       if ( ( guid_1 == 0x6553200cc000e48eULL ) && ( guid_2 == 0x11cfa9478cabdca1ULL ) )
  553.         {
  554.           packet_length = mms_get_32 ( header, i+92-24 );
  555.  
  556.           if ( packet_length != mms_get_32(header, i+72) )
  557.             warning ( NULL, "size of media packets is not constant, it should not happen" );
  558.  
  559.           if ( mms->stddebug != NULL )
  560.             {
  561.               fprintf ( mms->stddebug, "File Properties Object (%lld bytes)\n", length );
  562.               fprintf ( mms->stddebug, " -> broadcast bit: %d\n", mms_get_32(header,i+64)&1 );
  563.               fprintf ( mms->stddebug, " -> min packet length: %d\n", packet_length );
  564.               fprintf ( mms->stddebug, " -> max packet length: %d\n", mms_get_32(header, i+72) );
  565.               fprintf ( mms->stddebug, " -> number of media packets: %d\n\n", mms_get_32(header, i+32) );
  566.             }
  567.  
  568.           if ( mms_get_32(header,i+64)&1 )
  569.             {
  570.               if ( ( !mms->quiet ) && ( !mms->is_live ) )
  571.                 warning ( NULL, "stream seems to be live, an error may occur" );
  572.  
  573.               mms->is_live = MMS_LIVE;
  574.             }
  575.         }
  576.       else if  ( ( guid_1 == 0x6553200cc000e68eULL ) && ( guid_2 == 0x11cfa9b7b7dc0791ULL ) )
  577.         {
  578.           int stream_id = header[i+48] | header[i+49] << 8;
  579.  
  580.           if ( mms->num_stream_ids < 20 )
  581.             {
  582.               mms->stream_ids[mms->num_stream_ids] = stream_id;
  583.               ++mms->num_stream_ids;
  584.             }
  585.           else
  586.             {
  587.               if ( !mms->quiet )
  588. #ifdef HAVE_VSNPRINTF
  589.                 warning ( "mms_interp_header", "too many streams, stream \'%d\' skipped", stream_id );
  590. #else
  591.                 warning ( "mms_interp_header", "too many streams, skipping.." );
  592. #endif
  593.             }
  594.  
  595.           if ( mms->stddebug != NULL )
  596.             {
  597.               fprintf ( mms->stddebug, "Stream Object (%lld bytes)\n", length );
  598.               fprintf ( mms->stddebug, " -> stream id: %d\n\n", stream_id );
  599.             }
  600.         }
  601.       else if ( ( guid_1 == 0x6cce6200aa00d9a6ULL ) && ( guid_2 == 0x11cf668e75b22636ULL ) )
  602.         {
  603.           mms->expected_file_size += ( length - 50 ); /* valid values are at least 50 bytes (why?) */
  604.  
  605.           if ( mms->stddebug != NULL )
  606.             fprintf ( mms->stddebug, "Data Object (%lld bytes)\n\n", length );
  607.         }
  608.       else if ( mms->stddebug != NULL )
  609.         {
  610.           if ( ( guid_1 == 0x6cce6200aa00d9a6ULL ) && ( guid_2 == 0x11cf668e75b22630ULL ) )
  611.             fprintf ( mms->stddebug, "Header Object (%lld bytes)\n\n", length );
  612.           else if ( ( guid_1 == 0xcb4903c9a000f489ULL ) && ( guid_2 == 0x11cfe5b133000890ULL) )
  613.             fprintf ( mms->stddebug, "Simple Index Object (%lld bytes)\n\n", length );
  614.           else if ( ( guid_1 == 0xbe4903c9a0003490ULL ) && ( guid_2 == 0x11d135dad6e229d3ULL) )
  615.             fprintf ( mms->stddebug, "Index Object (%lld bytes)\n\n", length );
  616.           else if ( ( guid_1 == 0x6553200cc000e38eULL ) && ( guid_2 == 0x11cfa92e5fbf03b5ULL) )
  617.             fprintf ( mms->stddebug, "Header Extension Object (%lld bytes)\n\n", length );
  618.           else if ( ( guid_1 == 0x6cce6200aa00d9a6ULL ) && ( guid_2 == 0x11cf668e75b22633ULL) )
  619.             fprintf ( mms->stddebug, "Content Description Object (%lld bytes)\n\n", length );
  620.           else if ( ( guid_1 == 0x50a85ec9a000f097ULL ) && ( guid_2 == 0x11d2e307d2d0a440ULL) )
  621.             fprintf ( mms->stddebug, "Extended Content Description Object (%lld bytes)\n\n", length );
  622.           else if ( ( guid_1 == 0xf64803c9a000a4a3ULL ) && ( guid_2 == 0x11d0311d86d15240ULL) )
  623.             fprintf ( mms->stddebug, "Codec List Object (%lld bytes)\n\n", length );
  624.           else if ( ( guid_1 == 0xb2a2c9976000828dULL ) && ( guid_2 == 0x11d1468d7bf875ceULL) )
  625.             fprintf ( mms->stddebug, "Stream Bitrate Properties Object (%lld bytes)\n\n", length );
  626.           else
  627.             fprintf ( mms->stddebug, "Unknown Object (%lld bytes)\n\n", length );
  628.         }
  629.  
  630.       i += length-24;
  631.   }
  632.  
  633.   return packet_length;
  634. }
  635.  
  636.  
  637. /*
  638.  * Gets a media packet.
  639.  * Returns the amount of bytes in the media packet (0 if EOF), MMS_RET_ACKED if ACKed,
  640.  * MMS_RET_NO_AUTH if authorization failed, MMS_RET_ERROR either.
  641.  */
  642. static ssize_t
  643. mms_recv_media_packet ( MMS *mms,
  644.                         MMS_PACKET *pak )
  645. {
  646.   MMS_PACKET pre_header;
  647.   ssize_t packet_len;
  648.  
  649.   if ( mms_recv_packet ( mms->socket, &pre_header, 8, mms->quiet ) != 0 )
  650.     {
  651.       if ( !mms->quiet )
  652.         error ( "mms_recv_media_packet", "unable to get pre-header" );
  653.  
  654.       return MMS_RET_ERROR;
  655.     }
  656.  
  657.   if ( pre_header.buf[4] == 0x04 )
  658.     {
  659.       if ( mms->stddebug != NULL )
  660.         {
  661.           fprintf ( mms->stddebug, "\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n" );
  662.           fprintf ( mms->stddebug, " getting media packet from server\n\n" );
  663.         }
  664.  
  665.       if ( mms->stddebug != NULL )
  666.         {
  667.           static int i; /* static, so we don't recreate it for each call */
  668.  
  669.           for ( i=0; i<8; i++ )
  670.             fprintf ( mms->stddebug, "pre_header[%d] = 0x%02x (%d)\n", i, pre_header.buf[i], pre_header.buf[i] );
  671.         }
  672.  
  673.       packet_len = (pre_header.buf[7] << 8 | pre_header.buf[6]) - 8;
  674.  
  675.       if ( mms->stddebug != NULL )
  676.         fprintf ( mms->stddebug, "\nASF Media Packet (%d bytes)\n", packet_len );
  677.  
  678.       memset ( pak->buf, 0, mms->media_packet_len );
  679.  
  680.       if ( mms_recv_packet (mms->socket, pak, packet_len, mms->quiet) != 0 )
  681.         {
  682.           if ( !mms->quiet )
  683.             error ( "mms_recv_media_packet", "unable to get media packet" );
  684.  
  685.           return MMS_RET_ERROR;
  686.         }
  687.     }
  688.   else
  689.     {
  690.       int command = mms_recv_cmd_packet ( mms->socket, pak, &packet_len, 8, mms->quiet );
  691.  
  692.       if ( command == MMS_RET_ERROR )
  693.         {
  694.           if ( !mms->quiet )
  695.             error ( "mms_recv_media_packet", "unable to get cmd packet" );
  696.  
  697.           return MMS_RET_ERROR;
  698.         }
  699.  
  700.       memcpy ( pak->buf, pre_header.buf, 8 );
  701.  
  702.       if ( mms->stddebug != NULL )
  703.         mms_print_packet ( mms->stddebug, pak, packet_len, MMS_SERVER );
  704.  
  705.       if ( command == MMS_CMD_PING )
  706.         {
  707.           mms_send_packet ( mms, MMS_CMD_PONG, 0, 0, 0, pak->buf );
  708.           return MMS_RET_ACKED;
  709.         }
  710.       else if ( command == MMS_CMD_END_OF_STREAM )
  711.         return 0;
  712.       else if ( command == MMS_CMD_STREAM_SELECT_ACK ) /* it happens sometimes */
  713.         return MMS_RET_ACKED;
  714.       else if ( command == MMS_CMD_READY_TO_STREAM ) /* it always happen before the first media packet */
  715.         {
  716.           /* this happens on some server for some unknown reason */
  717.           if ( mms_get_32(pak->buf, 40) == 0x80070005 )
  718.             {
  719.               if ( !mms->quiet )
  720.                 error ( "mms_recv_media_packet", "streaming denied (read manpage & retry later)" );
  721.  
  722.               return MMS_RET_NO_AUTH;
  723.             }
  724.  
  725.           return MMS_RET_ACKED;
  726.         }
  727.       else
  728.         {
  729.           if ( !mms->quiet )
  730. #ifdef HAVE_VSNPRINTF
  731.             error ( "mms_recv_media_packet", "unknown command 0x%02x\n", command );
  732. #else
  733.             error ( "mms_recv_media_packet", "unknown command\n" );
  734. #endif
  735.  
  736.           return MMS_RET_ERROR;
  737.         }
  738.     }
  739.  
  740.   if ( mms->stddebug != NULL )
  741.     fprintf ( mms->stddebug, "\n" );
  742.  
  743.   return packet_len;
  744. }
  745.  
  746.  
  747. /*
  748.  * Creates An MMS Struct
  749.  * Returns an initialized MMS Struct if successful, NULL if an error occurs.
  750.  * url must start with mms:// or mmst:// (mmsu:// and mmsh:// are OK too, but we won't use UDP or do MMS over HTTP)
  751.  * trick must be MMS_TRICK_DISABLED or MMS_TRICK_ENABLED
  752.  */
  753. MMS *
  754. mms_create ( const char *url,
  755.              FILE *out,
  756.              FILE *stddebug,
  757.              const int trick,
  758.              const int quiet )
  759. {
  760.   MMS *mms;
  761.   register const char *sep;
  762.   register const int host_idx = mms_check_protocol ( url );
  763.   register const int url_len = strlen ( url );
  764.  
  765.   if ( stddebug != NULL )
  766.     {
  767.       fprintf ( stddebug, "\n\n********************************************************************************\n\n" );
  768.       fprintf ( stddebug, "Url -> \'%s\'\n", url );
  769.     }
  770.  
  771.   if ( host_idx == MMS_RET_ERROR )
  772.     {
  773.       if ( !quiet )
  774.         error ( "mms_create", "bad protocol (mms:// was expected)" );
  775.  
  776.       return NULL;
  777.     }
  778.  
  779.   sep = strchr ( &url[host_idx], '/' );
  780.  
  781.   if ( sep == NULL )
  782.     {
  783.       if ( !quiet )
  784.         error ( "mms_create", "url seems to be malformed" );
  785.  
  786.       return NULL;
  787.     }
  788.  
  789.   if ( ( mms = ( MMS * ) malloc ( sizeof(MMS) ) ) == NULL )
  790.     {
  791.       if ( !quiet )
  792.         error ( "mms_create", "unable to allocate memory" );
  793.  
  794.       return NULL;
  795.     }
  796.  
  797.   mms->host = malloc ( ( sep - &url[host_idx] ) + 1 );
  798.   strncpy ( mms->host, &url[host_idx], (sep - &url[host_idx]) );
  799.   mms->host[sep-&url[host_idx]] = '\0'; /* strndup */
  800.  
  801.   mms->path = strdup ( sep+1 );
  802.   mms->out = out;
  803.   mms->seq_num = 0;
  804.   mms->expected_file_size = 0;
  805.   mms->is_live = MMS_NO_LIVE;
  806.  
  807.   /* we try to guess stream type with the filename extension */
  808.   if ( ( sep = strchr(sep,'?') ) != NULL )
  809.     {
  810.       if ( ( *(sep-4) == '.' ) && /* this will never segfault because */
  811.            ( *(sep-3) == 'w' ) && /* the url is at least 6 chars long (mms://) */
  812.            ( *(sep-2) == 'm' ) &&
  813.            ( *(sep-1) == 'v' ) )
  814.         mms->stream_type = MMS_WMV;
  815.       else
  816.         mms->stream_type = MMS_ASF;
  817.     }
  818.   else
  819.     {
  820.       if ( ( url[url_len-4] == '.' ) &&
  821.            ( url[url_len-3] == 'w' ) &&
  822.            ( url[url_len-2] == 'm' ) &&
  823.            ( url[url_len-1] == 'v' ) )
  824.         mms->stream_type = MMS_WMV;
  825.       else
  826.         mms->stream_type = MMS_ASF;
  827.     }
  828.  
  829.   mms->stddebug = stddebug;
  830.   mms->quiet = quiet;
  831.   mms->trick = ( ((trick==MMS_TRICK_DISABLED)||(trick==MMS_TRICK_ENABLED)) ? trick : MMS_TRICK_DISABLED );
  832.  
  833.   if ( mms->stddebug != NULL )
  834.     {
  835.       fprintf ( mms->stddebug, "Host -> \'%s\'\nPath -> \'%s\'\n", mms->host, mms->path );
  836.       fprintf ( mms->stddebug, "Stream type -> %s\n", (mms->stream_type==MMS_WMV)?"MMS_WMV":"MMS_ASF" );
  837.     }
  838.  
  839.   return mms;
  840. }
  841.  
  842.  
  843. /*
  844.  * Establishes a connection with the MMS server.
  845.  * Returns MMS_RET_SUCCESS if success, MMS_RET_ERROR either.
  846.  */
  847. int
  848. mms_connect ( MMS* mms )
  849. {
  850.   struct sockaddr_in  sa;
  851.   struct hostent     *hp;
  852.  
  853.   if ( mms == NULL )
  854.     return -1;
  855.  
  856.   if ( ( hp = gethostbyname(mms->host) ) == NULL )
  857.     {
  858.       if ( !mms->quiet )
  859.         error ( "mms_connect", "unable to resolve host name" );
  860.  
  861.       return MMS_RET_ERROR;
  862.     }
  863.  
  864.   bcopy ( (char *) hp->h_addr, (char *) &sa.sin_addr, hp->h_length );
  865.   sa.sin_family = hp->h_addrtype;
  866.   sa.sin_port = htons ( 1755 );
  867.  
  868.   if ( ( mms->socket = socket(hp->h_addrtype, SOCK_STREAM, 0) ) == -1 )
  869.     {
  870.       if ( !mms->quiet )
  871. #ifdef HAVE_VSNPRINTF
  872.         error ( "mms_connect", "socket() said: %s", strerror(errno) );
  873. #else
  874.         error ( "mms_connect", "socket() failed" );
  875. #endif
  876.  
  877.       return  MMS_RET_ERROR;
  878.     }
  879.  
  880.   if ( connect ( mms->socket, (struct sockaddr *) &sa, sizeof sa ) != 0 )
  881.     {
  882.       if ( !mms->quiet )
  883. #ifdef HAVE_VSNPRINTF
  884.         error ( "mms_connect", "connect() said: %s", strerror(errno) );
  885. #else
  886.         error ( "mms_connect", "connect failed" );
  887. #endif
  888.  
  889.       return MMS_RET_ERROR;
  890.     }
  891.  
  892.   return MMS_RET_SUCCESS;
  893. }
  894.  
  895.  
  896. /*
  897.  * Handshake with the MMS server.
  898.  * ( we don't care about server's answers )
  899.  */
  900. int
  901. mms_handshake ( MMS *mms )
  902. {
  903.   MMS_PACKET pak;
  904.   int cmd = MMS_CMD_PING;
  905.   ssize_t packet_len;
  906.   char str [ 1024 ];
  907.   uint8_t data [ 2092 ];
  908.  
  909.   if ( mms == NULL )
  910.     return MMS_RET_ERROR;
  911.  
  912.   /* who we are */
  913.   memset ( data, 0, sizeof (data) );
  914.  
  915.   if ( mms->trick == MMS_TRICK_DISABLED )
  916.     {
  917. #ifdef HAVE_SNPRINTF
  918.       snprintf ( str, sizeof(str), "\034\003NSPlayer/7.0.0.1956; {3300AD50-2C39-46c0-AE0A-60181587CBA}; Host: %s", mms->host );
  919. #else
  920.       if ( (strlen("\034\003NSPlayer/7.0.0.1956; {3300AD50-2C39-46c0-AE0A-60181587CBA}; Host: ")+strlen(mms->host)) < sizeof(str) )
  921.         sprintf ( str, "\034\003NSPlayer/7.0.0.1956; {3300AD50-2C39-46c0-AE0A-60181587CBA}; Host: %s", mms->host );
  922.       else
  923.         {
  924.           error ( "mms_handshake", "host name is too long" );
  925.           return MMS_RET_ERROR;
  926.         }
  927. #endif
  928.     }
  929.   else
  930.     strcpy ( str, "\034\003NSPlayer/4.1.0.3928; {3300AD50-2C39-46c0-AE0A-60181587CBA}" );
  931.  
  932.   mms_string_utf16 ( data, (unsigned char *) str, strlen(str)+2 );
  933.   mms_send_packet ( mms, MMS_CMD_HELLO, 0, 0x0004000b, strlen(str)*2 + 6, data );
  934.  
  935.   cmd = MMS_CMD_PING;
  936.   while ( cmd == MMS_CMD_PING )
  937.     {
  938.       cmd = mms_recv_cmd_packet ( mms->socket, &pak, &packet_len, 0, mms->quiet );
  939.  
  940.       if ( cmd == MMS_CMD_PING )
  941.         mms_send_packet ( mms, MMS_CMD_PONG, 0, 0, 0, pak.buf );
  942.     }
  943.  
  944.   if ( cmd == MMS_CMD_INVALID )
  945.     {
  946.       if ( !mms->quiet )
  947.         error ( "mms_handshake", "unable to get cmd packet" );
  948.  
  949.       return MMS_RET_ERROR;
  950.     }
  951.  
  952.   if ( mms->stddebug != NULL )
  953.     mms_print_packet ( mms->stddebug, &pak, packet_len, MMS_SERVER );
  954.  
  955.   /* transport protocol selection */
  956.   memset ( &data, 0, sizeof(data) );
  957.   mms_string_utf16 ( &data[8], (unsigned char *) "\002\000\\\\192.168.0.129\\TCP\\1037\0000", 28 );
  958.   mms_send_packet ( mms, MMS_CMD_PROTOCOL_SELECT, 0, 0, 28*2+8, data );
  959.  
  960.   cmd = MMS_CMD_PING;
  961.   while ( cmd == MMS_CMD_PING )
  962.     {
  963.       cmd = mms_recv_cmd_packet ( mms->socket, &pak, &packet_len, 0, mms->quiet );
  964.  
  965.       if ( cmd == MMS_CMD_PING )
  966.         mms_send_packet ( mms, MMS_CMD_PONG, 0, 0, 0, pak.buf );
  967.     }
  968.  
  969.   if ( cmd == MMS_CMD_INVALID )
  970.     {
  971.       if ( !mms->quiet )
  972.         error ( "mms_handshake", "unable to get cmd packet" );
  973.  
  974.       return MMS_RET_ERROR;
  975.     }
  976.  
  977.   if ( mms->stddebug != NULL )
  978.     mms_print_packet ( mms->stddebug, &pak, packet_len, MMS_SERVER );
  979.  
  980.   /* requested file */
  981.   mms_string_utf16 ( &data[8], (unsigned char *) mms->path, strlen(mms->path) );
  982.   memset ( data, 0, 8 );
  983.   mms_send_packet ( mms, MMS_CMD_FILE_REQUEST, 0, 0, strlen(mms->path)*2+12, data );
  984.  
  985.   cmd = MMS_CMD_PING;
  986.   while ( cmd == MMS_CMD_PING )
  987.     {
  988.       cmd = mms_recv_cmd_packet ( mms->socket, &pak, &packet_len, 0, mms->quiet );
  989.  
  990.       if ( cmd == MMS_CMD_PING )
  991.         mms_send_packet ( mms, MMS_CMD_PONG, 0, 0, 0, pak.buf );
  992.     }
  993.  
  994.   if ( cmd == MMS_CMD_INVALID )
  995.     {
  996.       if ( !mms->quiet )
  997.         error ( "mms_handshake", "unable to get cmd packet" );
  998.  
  999.       return MMS_RET_ERROR;
  1000.     }
  1001.  
  1002.   if ( cmd == MMS_CMD_STREAM_INFOS )
  1003.     {
  1004.       if ( mms_get_32 ( pak.buf, 48 ) == -1 )
  1005.         {
  1006.           if ( !mms->quiet )
  1007.             error ( "mms_handshake", "stream infos are not available" );
  1008.  
  1009.           return MMS_RET_ERROR;
  1010.         }
  1011.  
  1012.       if ( ( mms_get_32(pak.buf,72) == 0 ) || ( mms_get_32(pak.buf,72) == 0xFFFFFFFF ) )
  1013.         {
  1014.           mms->is_live = MMS_LIVE;
  1015.  
  1016.           if ( !mms->quiet )
  1017.             warning ( NULL, "stream seems to be live, an error may occur" );
  1018.         }
  1019.     }
  1020.  
  1021.   if ( mms->stddebug != NULL )
  1022.     mms_print_packet ( mms->stddebug, &pak, packet_len, MMS_SERVER );
  1023.  
  1024.   return MMS_RET_SUCCESS;
  1025. }
  1026.  
  1027.  
  1028. /*
  1029.  * Gets ASF/WMV stream/file header
  1030.  */
  1031. ssize_t
  1032. mms_write_stream_header ( MMS *mms )
  1033. {
  1034.   MMS_PACKET pak;
  1035.   ssize_t len;
  1036.  
  1037.   if ( mms == NULL )
  1038.     return MMS_RET_ERROR;
  1039.  
  1040.   /* give me the stream header please... */
  1041.   memset ( pak.buf, 0, 40 );
  1042.   pak.buf[32] = 2;
  1043.   mms_send_packet ( mms, MMS_CMD_HEADER_REQUEST, 1, 0, 40, pak.buf );
  1044.  
  1045.   len = mms_recv_header_packet ( mms, &pak );
  1046.  
  1047.   if ( len == -1 )
  1048.     {
  1049.       if ( !mms->quiet )
  1050.         error ( "mms_get_stream_header", "unable to get stream header\n" );
  1051.  
  1052.       return MMS_RET_ERROR;
  1053.     }
  1054.   else if ( len == 0 )
  1055.     {
  1056.       if ( !mms->quiet )
  1057.         error ( "mms_get_stream_header", "no stream header available, file may not exist" );
  1058.  
  1059.       return MMS_RET_ERROR;
  1060.     }
  1061.  
  1062.   fwrite ( pak.buf, len, 1, mms->out );
  1063.  
  1064.   mms->media_packet_len = mms_interp_header ( mms, pak.buf, len );
  1065.  
  1066.   if ( mms->media_packet_len > MMS_BUF_SIZE )
  1067.     {
  1068.       if ( !mms->quiet )
  1069.         error ( "mms_get_stream_header", "media packet length is too big for me" );
  1070.  
  1071.       return MMS_RET_ERROR;
  1072.     }
  1073.  
  1074.   return len;
  1075. }
  1076.  
  1077.  
  1078. /*
  1079.  * Tells the server we're ready to rip the stream from the beginning (don't know what happens if it's a live)
  1080.  * Returns 0 if success, -1 either.
  1081.  */
  1082. int
  1083. mms_begin_rip ( MMS *mms )
  1084. {
  1085.   int i;
  1086.   uint8_t data [ 1024 ];
  1087.   MMS_PACKET pak;
  1088.   ssize_t packet_len;
  1089.   int cmd;
  1090.  
  1091.   if ( mms == NULL )
  1092.     return MMS_RET_ERROR;
  1093.  
  1094.   /* media stream selection */
  1095.   memset ( data, 0, 40 );
  1096.  
  1097.   for ( i=1; i<mms->num_stream_ids; ++i )
  1098.     {
  1099.       data [ (i-1) * 6 + 2 ] = 0xFF;
  1100.       data [ (i-1) * 6 + 3 ] = 0xFF;
  1101.       data [ (i-1) * 6 + 4 ] = mms->stream_ids[i];
  1102.       data [ (i-1) * 6 + 5 ] = 0x00;
  1103.     }
  1104.  
  1105.   /* we add the final bytes of the stream selector, necessary for ASF streams only */
  1106.   if ( mms->stream_type == MMS_ASF )
  1107.     {
  1108.       data [ (mms->num_stream_ids-1) * 6 + 0 ] = 0x00;
  1109.       data [ (mms->num_stream_ids-1) * 6 + 1 ] = 0x00;
  1110.       data [ (mms->num_stream_ids-1) * 6 + 2 ] = 0x00;
  1111.       data [ (mms->num_stream_ids-1) * 6 + 3 ] = 0x20;
  1112.       data [ (mms->num_stream_ids-1) * 6 + 4 ] = 0xac;
  1113.       data [ (mms->num_stream_ids-1) * 6 + 5 ] = 0x40;
  1114.       data [ (mms->num_stream_ids-1) * 6 + 6 ] = 0x02;
  1115.  
  1116.       mms_send_packet ( mms, MMS_CMD_STREAM_SELECT, mms->num_stream_ids, 0xFFFF | mms->stream_ids[0] << 16, (mms->num_stream_ids-1)*6+2+4, data );
  1117.     }
  1118.   else
  1119.     {
  1120.       mms_send_packet ( mms, MMS_CMD_STREAM_SELECT, mms->num_stream_ids, 0xFFFF | mms->stream_ids[0] << 16, (mms->num_stream_ids-1)*6+2, data );
  1121.     }
  1122.  
  1123.   cmd = MMS_CMD_PING;
  1124.   while ( cmd == MMS_CMD_PING )
  1125.     {
  1126.       cmd = mms_recv_cmd_packet ( mms->socket, &pak, &packet_len, 0, mms->quiet );
  1127.  
  1128.       if ( cmd == MMS_CMD_PING )
  1129.         mms_send_packet ( mms, MMS_CMD_PONG, 0, 0, 0, pak.buf );
  1130.     }
  1131.  
  1132.   if ( cmd == MMS_CMD_INVALID )
  1133.     {
  1134.       if ( !mms->quiet )
  1135.         error ( "mms_begin_rip", "unable to get server\'s confirmation" );
  1136.  
  1137.       return MMS_RET_ERROR;
  1138.     }
  1139.  
  1140.   if ( mms->stddebug != NULL )
  1141.     mms_print_packet ( mms->stddebug, &pak, packet_len, MMS_SERVER );
  1142.  
  1143.  
  1144.   /* ready... */
  1145.   memset ( data, 0, 40 );
  1146.  
  1147.   for ( i=8; i<16; ++i )
  1148.     data[i] = 0xFF;
  1149.  
  1150.   data[20] = 0x04;
  1151.  
  1152.   mms_send_packet ( mms, MMS_CMD_START_PACKET, 1, 0xFFFF | mms->stream_ids[0] << 16, 24, data );
  1153.  
  1154.   return MMS_RET_SUCCESS;
  1155. }
  1156.  
  1157.  
  1158. /*
  1159.  * Writes a media packet.
  1160.  * Returns the amount of bytes written, 0 if EOF, MMS_RET_NO_AUTH if streaming is denied, MMS_RET_ERROR either.
  1161.  */
  1162. ssize_t
  1163. mms_write_stream_data ( MMS *mms )
  1164. {
  1165.   ssize_t len;
  1166.   MMS_PACKET pak;
  1167.  
  1168.   if ( mms == NULL )
  1169.     return 0;
  1170.   
  1171.   do
  1172.     {
  1173.       len = mms_recv_media_packet ( mms, &pak );
  1174.     }
  1175.   while ( len == MMS_RET_ACKED ); /* while we receive ACK packets */
  1176.  
  1177.   if ( len == 0 )
  1178.     return 0;
  1179.   else if ( len == -1 )
  1180.     {
  1181.       if ( !mms->quiet )
  1182.         error ( "mms_write_stream_data", "mms_recv_media_packet failed" );
  1183.  
  1184.       return MMS_RET_ERROR;
  1185.     }
  1186.   else if ( len == MMS_RET_NO_AUTH )
  1187.     {
  1188.       if ( !mms->quiet )
  1189.         error ( "mms_write_stream_data", "mms_recv_media_packet failed" );
  1190.  
  1191.       return MMS_RET_NO_AUTH;
  1192.     }
  1193.  
  1194.   fwrite ( pak.buf, mms->media_packet_len, 1, mms->out ); /* we might have read less than the arbitrary media packet size */
  1195.  
  1196.   return mms->media_packet_len;
  1197. }
  1198.  
  1199.  
  1200. /*
  1201.  * Closes the connection.
  1202.  */
  1203. void
  1204. mms_disconnect ( MMS *mms )
  1205. {
  1206.   uint8_t data [ 1024 ];
  1207.  
  1208.   if ( mms == NULL )
  1209.     return;
  1210.  
  1211.   mms_send_packet ( mms, MMS_CMD_BYE_BYE, 0, 0, 0, data );
  1212.  
  1213.   if ( ( shutdown(mms->socket, SHUT_RDWR) | close(mms->socket)) != 0 )
  1214.     if ( !mms->quiet )
  1215.       warning ( "mms_disconnect", "unable to close the socket properly" );
  1216.  
  1217.   return;
  1218. }
  1219.  
  1220.  
  1221. /*
  1222.  * Destroys An MMS Struct
  1223.  */
  1224. void
  1225. mms_destroy ( MMS *mms )
  1226. {
  1227.   if ( mms == NULL )
  1228.     return;
  1229.  
  1230.   if ( mms->host != NULL )
  1231.     free ( mms->host );
  1232.  
  1233.   if ( mms->path != NULL )
  1234.     free ( mms->path );
  1235.  
  1236.   free ( mms );
  1237.  
  1238.   return;
  1239. }
  1240.